/**
 * @file    wifi_sntp.c
 * @author  Azolla (1228449928@qq.com)
 * @brief   using LwIP SNTP module and time functions
 * @version 0.1
 * @date    2022-11-03
 * 
 * @copyright Copyright (c) 2022
 * */
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_sntp.h"
 
#include "wifi_init.h"
#include "wifi_sntp.h"

static SemaphoreHandle_t xSemaphore = NULL; 

#define TAG   "wifi_sntp"

#define SNTP_SERVER_ENABLE  1

#if !SNTP_SERVER_ENABLE
// 自定义校准本地时间同步！
// lwip/include/apps/esp_sntp.h:81:6: note: previous declaration of 'sntp_sync_time' was here
void sntp_sync_time(struct timeval *tv)  
{
    ESP_LOGI(TAG, "synchronization[custom] -> tv_sec: %lld", tv->tv_sec);
    settimeofday(tv, NULL);
    sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED);
    setenv("TZ", "CST-8", 1);
    tzset();
}
 
void sntp_sync_time_custom(time_t timestamp)
{
    struct timeval tv = { 0 };
    tv.tv_sec = timestamp + 28800;  // +8小时时区(8 * 3600)
    sntp_sync_time(&tv); 
}
#endif
 
struct tm * sntp_gmtime(void)
{
    time_t now = 0;
    time(&now);     // update 'now' variable with current time
    struct tm *sntp = gmtime(&now);
    sntp->tm_year += 1900;
    sntp->tm_mon  += 1;
    sntp->tm_wday += 1;
    #if 1 // #ifdef TAG
    ESP_LOGI("SNTP", "%d-%02d-%02d %02d:%02d:%02d %d", 
            sntp->tm_year, sntp->tm_mon, sntp->tm_mday,
            sntp->tm_hour, sntp->tm_min, sntp->tm_sec, sntp->tm_wday);
    #endif
    return sntp;
}
 
// Mon Oct 14 10:30:57 2024 
void sntp_strtime(char *strtime, struct tm *curtime)
{
    time_t now = 0;
    time(&now); // update 'now' variable with current time
    localtime_r(&now, curtime);
    strftime(strtime, 32, "%c", curtime);
    //strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", ptm);
    #if 0 // #ifdef TAG
    sntp->tm_year += 1900;
    sntp->tm_mon  += 1;
    sntp->tm_wday += 1;
    struct tm *sntp = curtime;
    ESP_LOGI("SNTP", "%d-%02d-%02d %02d:%02d:%02d %d", 
            sntp->tm_year, sntp->tm_mon, sntp->tm_mday,
            sntp->tm_hour, sntp->tm_min, sntp->tm_sec, sntp->tm_wday);
    #endif
}

void sntp_print_time(void)
{
    struct tm curtime;
    char strtime[32];
    sntp_strtime(strtime, &curtime);  
    ESP_LOGI(TAG, "strtime = %s", strtime);
}

#if SNTP_SERVER_ENABLE

bool sntp_sync_wait(uint32_t wait_time) 
{
    return xSemaphoreTake(xSemaphore, wait_time / portTICK_PERIOD_MS);
}


// menuconfig -> Component config -> LWIP -> SNTP -> [30000] Request interval to update time (ms).
void time_sync_notification_cb(struct timeval *tv)
{
    // Set timezone to China Standard Time
    ESP_LOGI(TAG, "synchronization[sntp] -> tv_sec: %ld", tv->tv_sec);
    if (tv->tv_sec < 1070366820) return;  // 校准时间不对！
    // setenv("TZ", "CST-0", 1);
    // setenv("TZ", "CST-8", 1);
    // setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1);
    setenv("TZ", "GMT+0", 1);
    tzset();
    esp_sntp_stop();  // 获取到同步时间后，暂停SNTP服务器, 防止重启获取不到时间了

    xSemaphoreGive(xSemaphore);
}

static void initialize_sntp(void)
{
    ESP_LOGI(TAG, "Initializing SNTP");
    esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL);
    esp_sntp_setservername(0, "ntp.aliyun.com");
    esp_sntp_setservername(1, "edu.ntp.org.cn");
    esp_sntp_setservername(2, "cn.ntp.org.cn");
    // sntp_setservername(2, "ntp.ntsc.ac.cn");
    // https://www.jianshu.com/p/6a98909a06d5
    sntp_set_time_sync_notification_cb(time_sync_notification_cb);
    esp_sntp_init();
}

void wifi_sntp_task(void *arg)
{ 
    wifi_connect_status(portMAX_DELAY);  // 先等待WIFI连接上
#ifdef LWIP_DHCP_GET_NTP_SRV
    sntp_servermode_dhcp(1);
#endif
    initialize_sntp();

#if 0  // test...
    while (1) {
        sntp_print_time();
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }  
#endif  
    vTaskDelete(NULL);
}

void wifi_sntp_init(void)
{
    xSemaphore = xSemaphoreCreateBinary();
    xTaskCreatePinnedToCore(wifi_sntp_task, "wifi_sntp", 3 * 1024, NULL, 5, NULL, PRO_CPU_NUM); 
}
#endif
